package ca.compsci.opent.compiler.codegen;

import static org.objectweb.asm.Opcodes.*;

import java.io.File;
import java.io.FileNotFoundException;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;

import ca.compsci.opent.compiler.analysis.*;
import ca.compsci.opent.compiler.semantics.*;
import ca.compsci.opent.compiler.node.*;

public class BytecodeGenerator extends DepthFirstAdapter {
	private ClassWriter cw;
	private MethodVisitor mv;
	
	private SymbolTable scope;
	
	public static final String CLASS_NAME = "Main";
	
	public BytecodeGenerator(File dir, SymbolTable table) throws FileNotFoundException {
		if ((this.scope = table) == null)
			throw new NullPointerException("No symbol table provided");
		if (dir == null)
			dir = new File(".");
	}
	
	@Override
	public void caseAProgram(AProgram node) {
		cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
		cw.visit(V1_4, ACC_PUBLIC + ACC_FINAL, CLASS_NAME, null, "java/lang/Object", null);
		mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC + ACC_FINAL, "main", "([Ljava/lang/String;)V", null, null);
		
		BytecodeInsnGenerator insn_gen = new BytecodeInsnGenerator(mv, 1, scope);
		node.apply(insn_gen);
		
		mv.visitInsn(RETURN);
		mv.visitMaxs(insn_gen.getStackSize(), insn_gen.getLocalsSize());
		mv.visitEnd();
		
		// TODO: visit other methods
		
		cw.visitEnd();
	}
	
	public byte[] getBytecode() {
		return cw.toByteArray();
	}
}
